package Git

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
)

const (
	BaseWorkUrl    = "/usershen/user_work"         //用户工作目录
	BaseInterimUrl = "/usershen/user_work_interim" //用户克隆过渡目录
	BaseBackupUrl  = "/usershen/user_work_backup"  //用户代码备份目录
)

//	DeleteDirectory
//
// 描述信息：删除指定的目录及其所有内容, 如果目录存在，则删除；如果目录不存在，则不做任何操作。
//
// Param：
//
//	dirPath ：指定文件目录
//
// Return：
//
//	bool ：表示操作是否成功
//	error ：如果操作失败，返回具体的错误信息；否则返回 nil。
func DeleteDirectory(dirPath string) (bool, error) {
	// 检查目录是否存在
	if _, err := os.Stat(dirPath); os.IsNotExist(err) {
		// 目录不存在，无需删除
		return true, nil
	} else if err != nil {
		// 其他错误
		return false, fmt.Errorf("检查目录时出错: %v", err)
	}

	// 目录存在，删除目录及其所有内容
	if err := os.RemoveAll(dirPath); err != nil {
		return false, fmt.Errorf("删除目录失败: %v", err)
	}

	// 删除成功
	return true, nil
}

//	CloneRepository
//
// 描述信息： 在过渡目录中执行 Git 克隆操作，并将克隆的内容复制到工作目录 同时，将工作目录的内容备份到备份目录
//
// Param：
//
//	projectURL ：项目的 http url地址
//	userID ：用户id
//	teamID ：团队id
//	path ：git克隆时会自动生成的目录名称
//
// Return：
//
//	error ：错误信息
func CloneRepository(projectURL string, userID string, teamID string, path string) error {
	// 构建目录路径
	workDir := filepath.Join(BaseWorkUrl, userID, teamID)
	interimDir := filepath.Join(BaseInterimUrl, userID, teamID)
	backupDir := filepath.Join(BaseBackupUrl, userID, teamID)
	interimPathDir := filepath.Join(interimDir, path)
	workPathDir := filepath.Join(workDir, path)
	backupPathDir := filepath.Join(backupDir, path)

	// 确保过渡目录存在
	if err := EnsureDirectoryExists(interimDir); err != nil {
		return fmt.Errorf("确保过渡目录存在失败: %v", err)
	}

	// 检查过渡目录是否存在 path 文件夹，如果存在，删除
	if _, err := DeleteDirectory(interimPathDir); err != nil {
		return fmt.Errorf("删除过渡目录中的 path 文件夹失败: %v", err)
	}

	// 构建 Git 克隆命令
	cloneCmd := fmt.Sprintf("git clone %s", projectURL)

	// 在过渡目录中执行 Git 克隆命令
	cmd := exec.Command("bash", "-c", cloneCmd)
	cmd.Dir = interimDir

	fmt.Println("正在执行 Git 克隆操作...")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("Git 克隆失败: %s, 错误: %v", output, err)
	}

	fmt.Println("Git 克隆成功！")

	// 确保备份目录存在
	if err := EnsureDirectoryExists(backupDir); err != nil {
		return fmt.Errorf("确保备份目录存在失败: %v", err)
	}

	// 检查备份目录是否存在 path 文件夹，如果存在，删除
	if _, err := DeleteDirectory(backupPathDir); err != nil {
		return fmt.Errorf("删除备份目录中的 path 文件夹失败: %v", err)
	}

	// 如果备份目录中不存在 path 文件夹，将工作目录中的 path 文件夹复制到备份目录
	if _, err := os.Stat(workPathDir); err == nil {
		if err := CopyDirectory(workPathDir, backupPathDir); err != nil {
			return fmt.Errorf("将工作目录中的 path 文件夹复制到备份目录失败: %v", err)
		}
		fmt.Println("工作目录中的 path 文件夹已成功备份到备份目录。")
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("检查工作目录中的 path 文件夹时出错: %v", err)
	}

	// 删除工作目录中的 path 文件夹
	if _, err := DeleteDirectory(workPathDir); err != nil {
		return fmt.Errorf("删除工作目录中的 path 文件夹失败: %v", err)
	}

	// 将过渡目录中的 path 文件夹复制到工作目录
	if err := CopyDirectory(interimPathDir, workPathDir); err != nil {
		return fmt.Errorf("将过渡目录中的 path 文件夹复制到工作目录失败: %v", err)
	}

	fmt.Println("克隆的内容已成功复制到工作目录。")
	return nil
}

// EnsureDirectoryExists 确保指定的目录存在，如果不存在则创建
func EnsureDirectoryExists(dirPath string) error {
	// 检查目录是否存在
	if _, err := os.Stat(dirPath); os.IsNotExist(err) {
		// 目录不存在，创建目录及其所有父目录
		if err := os.MkdirAll(dirPath, 0755); err != nil {
			return fmt.Errorf("创建目录失败: %v", err)
		}
	} else if err != nil {
		// 其他错误
		return fmt.Errorf("检查目录时出错: %v", err)
	}
	// 目录已存在，无需操作
	return nil
}

// CopyDirectory 将源目录的内容复制到目标目录
func CopyDirectory(src, dst string) error {
	// 创建目标目录
	if err := os.MkdirAll(dst, 0755); err != nil {
		return fmt.Errorf("创建目标目录失败: %v", err)
	}

	// 遍历源目录
	srcInfo, err := os.Stat(src)
	if err != nil {
		return fmt.Errorf("读取源目录信息失败: %v", err)
	}

	if !srcInfo.IsDir() {
		return fmt.Errorf("源路径不是一个目录")
	}

	files, err := os.ReadDir(src)
	if err != nil {
		return fmt.Errorf("读取源目录内容失败: %v", err)
	}

	for _, file := range files {
		srcPath := filepath.Join(src, file.Name())
		dstPath := filepath.Join(dst, file.Name())

		if file.IsDir() {
			// 递归复制子目录
			if err := CopyDirectory(srcPath, dstPath); err != nil {
				return err
			}
		} else {
			// 复制文件
			if err := CopyFile(srcPath, dstPath); err != nil {
				return err
			}
		}
	}

	return nil
}

// CopyFile 将单个文件从源路径复制到目标路径
func CopyFile(src, dst string) error {
	srcFile, err := os.Open(src)
	if err != nil {
		return fmt.Errorf("打开源文件失败: %v", err)
	}
	defer srcFile.Close()

	dstFile, err := os.Create(dst)
	if err != nil {
		return fmt.Errorf("创建目标文件失败: %v", err)
	}
	defer dstFile.Close()

	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return fmt.Errorf("复制文件内容失败: %v", err)
	}

	return nil
}
